using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace WPCoco.Graphics
{
    public class TextureNode : Node, IGraphicState, IColored
    {
        public TextureNode(AffineNode target, bool autoSize)
        {
            Target = target; AutoSize = autoSize;
        }

        public TextureNode(AffineNode target)
            : this(target, true)
        {

        }

        AffineNode target;

        public AffineNode Target
        {
            get { return target; }
            set
            {
                target = value;
                RemoveAll(true);
                if (target != null)
                    AddNode(target);
            }
        }

        protected override void HasBeenRemoved(Node node)
        {
            if (node == target) Target = null;
        }

        bool autoSize = true;

        public bool AutoSize
        {
            get { return autoSize; }
            set { autoSize = value; }
        }

        float width = 1;

        public float Width
        {
            get
            {
                if (autoSize) return target.Width;
                return width;
            }
            set
            {
                width = value;
            }
        }

        float height = 1;

        public float Height
        {
            get
            {
                if (autoSize) return target.Height;
                return height;
            }
            set
            {
                height = value;
            }
        }


        Matrix contentMatrix = Matrix.Identity;
        Matrix inverseMatrix = Matrix.Identity;

        float contentScale = 1;

        public float ContentScale
        {
            get { return contentScale; }
            set 
            {
                if (contentScale == value) return;
                contentScale = value;
                contentMatrix = Matrix.CreateScale(contentScale);
                inverseMatrix = Matrix.CreateScale(1.0f / contentScale);
            }
        }

        #region Drawing Stuff

        public override void Draw(GameTime gameTime)
        {
            if (target == null) return;
            Size size = new Size((int)(Width * contentScale), (int)(Height * contentScale));
            RenderTarget2D renderTarget = RenderTargetCache.RetainTargetWidthSize(size);

            RenderTargetBinding[] targets = Screen.CurrentGraphicsDevice.GetRenderTargets();
            Screen.CurrentGraphicsDevice.SetRenderTarget(renderTarget);

            Screen.CurrentGraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer | ClearOptions.Stencil, Color.Transparent, 0, 0);

            if (contentScale != 1.0f)
                WorldMatrix.Shared.Set(target.ViewWorldMatrix * contentMatrix);
            else
                WorldMatrix.Shared.Set(target.ViewWorldMatrix);
            target.Draw(gameTime);
            WorldMatrix.Shared.Pop();

            Screen.CurrentGraphicsDevice.SetRenderTargets(targets);

            if (filter != null)
                filter(renderTarget, size);
            if (contentScale != 1.0f)
                WorldMatrix.Shared.Set(inverseMatrix * target.WorldViewMatrix);
            else
                WorldMatrix.Shared.Set(target.WorldViewMatrix);
            DrawTexture(renderTarget, size);
            WorldMatrix.Shared.Pop();

            RenderTargetCache.ReleaseTarget(renderTarget);
        }

        public virtual void DrawTexture(Texture2D texture, Size size)
        {
            CachedSpriteBatch spriteBatch = SpriteBatchCache.GetVolatile();
            spriteBatch.Begin(SpriteSortMode.Deferred, blend, sampler, depthStencil, rasterizer, null, WorldMatrix.Shared.CurrentMatrix);
            Rectangle rect = new Rectangle(0, 0, size.Width, size.Height);
            spriteBatch.Draw(texture, rect, rect, Color);
            spriteBatch.End();
        }

        public delegate void Texture2DFilterMethod(Texture2D texture, Size size);

        Texture2DFilterMethod filter;

        public Texture2DFilterMethod Filter
        {
            get { return filter; }
            set { filter = value; }
        }

        #endregion

        #region IGraphicState Members

        SamplerState sampler;

        public SamplerState Sampler
        {
            get { return sampler; }
            set { sampler = value; }
        }

        DepthStencilState depthStencil;

        public DepthStencilState DepthStencil
        {
            get { return depthStencil; }
            set { depthStencil = value; }
        }

        BlendState blend = BlendState.AlphaBlend;

        public BlendState Blend
        {
            get { return blend; }
            set { blend = value; }
        }

        RasterizerState rasterizer;

        public RasterizerState Rasterizer
        {
            get { return rasterizer; }
            set { rasterizer = value; }
        }

        #endregion

        #region IColored Members

        Color color = Color.White;

        public virtual Color Color
        {
            get { return color; }
            set { color = value; }
        }

        #endregion
    }
}
